"""
策略基类
所有交易策略必须继承此基类并实现必要的方法
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Tuple
from datetime import datetime
import pandas as pd


class BaseStrategy(ABC):
    """交易策略基类"""
    
    def __init__(self, config: Dict):
        """
        初始化策略
        
        参数:
            config: 策略配置字典
        """
        self.config = config
        self.name = config.get('name', self.__class__.__name__)
        self.enabled = config.get('enabled', True)
        self.category = config.get('category', 'unknown')
        
        # 策略参数
        self.params = config.get('params', {})
        
        # 交易设置
        self.trading_config = config.get('trading', {})
        self.symbols = self.trading_config.get('symbols', [])
        self.leverage = self.trading_config.get('leverage', 1)
        self.position_size = self.trading_config.get('position_size', 0.1)
        
        # 风险控制
        self.risk_config = config.get('risk', {})
        self.stop_loss = self.risk_config.get('stop_loss', 0.02)
        self.take_profit = self.risk_config.get('take_profit', 0.04)
        self.trailing_stop = self.risk_config.get('trailing_stop', False)
        
        # 策略状态
        self.is_running = False
        self.positions = {}  # 当前持仓 {symbol: position_info}
        self.orders = {}  # 当前订单 {order_id: order_info}
        self.trades_history = []  # 交易历史
        
        # 性能统计
        self.stats = {
            'total_trades': 0,
            'winning_trades': 0,
            'losing_trades': 0,
            'total_profit': 0.0,
            'total_loss': 0.0,
            'max_drawdown': 0.0,
            'consecutive_losses': 0,
            'last_trade_time': None
        }
    
    @abstractmethod
    def generate_signal(self, symbol: str, market_data: pd.DataFrame) -> Dict:
        """
        生成交易信号（必须实现）
        
        参数:
            symbol: 交易对
            market_data: 市场数据（K线数据）
            
        返回:
            信号字典 {
                'action': 'buy' / 'sell' / 'close' / 'hold',
                'confidence': 0.0-1.0,
                'reason': '信号原因',
                'price': 建议价格（可选）
            }
        """
        pass
    
    @abstractmethod
    def calculate_position_size(self, symbol: str, signal: Dict, account_balance: float) -> float:
        """
        计算开仓数量（必须实现）
        
        参数:
            symbol: 交易对
            signal: 交易信号
            account_balance: 账户余额
            
        返回:
            开仓数量
        """
        pass
    
    def check_entry_conditions(self, symbol: str, signal: Dict) -> Tuple[bool, str]:
        """
        检查入场条件
        
        参数:
            symbol: 交易对
            signal: 交易信号
            
        返回:
            (是否允许入场, 原因)
        """
        # 检查策略是否启用
        if not self.enabled:
            return False, "策略未启用"
        
        # 检查策略是否运行中
        if not self.is_running:
            return False, "策略未运行"
        
        # 检查信号置信度
        if signal.get('confidence', 0) < 0.5:
            return False, f"信号置信度过低: {signal.get('confidence')}"
        
        # 检查是否已有持仓
        if symbol in self.positions:
            return False, f"已有持仓: {symbol}"
        
        # 检查连续亏损
        max_consecutive_losses = self.risk_config.get('max_consecutive_losses', 3)
        if self.stats['consecutive_losses'] >= max_consecutive_losses:
            return False, f"连续亏损{self.stats['consecutive_losses']}次，暂停交易"
        
        return True, "入场条件满足"
    
    def check_exit_conditions(self, symbol: str, current_price: float) -> Tuple[bool, str]:
        """
        检查出场条件
        
        参数:
            symbol: 交易对
            current_price: 当前价格
            
        返回:
            (是否应该出场, 原因)
        """
        if symbol not in self.positions:
            return False, "无持仓"
        
        position = self.positions[symbol]
        entry_price = position['entry_price']
        side = position['side']
        
        # 计算盈亏比例
        if side == 'long':
            pnl_ratio = (current_price - entry_price) / entry_price
        else:  # short
            pnl_ratio = (entry_price - current_price) / entry_price
        
        # 检查止损
        if pnl_ratio <= -self.stop_loss:
            return True, f"触发止损: {pnl_ratio:.2%}"
        
        # 检查止盈
        if pnl_ratio >= self.take_profit:
            return True, f"触发止盈: {pnl_ratio:.2%}"
        
        # 检查追踪止损
        if self.trailing_stop and 'highest_price' in position:
            if side == 'long':
                trailing_stop_price = position['highest_price'] * (1 - self.stop_loss)
                if current_price <= trailing_stop_price:
                    return True, f"触发追踪止损: 价格{current_price}, 止损位{trailing_stop_price}"
            else:  # short
                trailing_stop_price = position['lowest_price'] * (1 + self.stop_loss)
                if current_price >= trailing_stop_price:
                    return True, f"触发追踪止损: 价格{current_price}, 止损位{trailing_stop_price}"
        
        return False, "持仓中"
    
    def update_position(self, symbol: str, current_price: float):
        """
        更新持仓信息（用于追踪止损）
        
        参数:
            symbol: 交易对
            current_price: 当前价格
        """
        if symbol not in self.positions:
            return
        
        position = self.positions[symbol]
        side = position['side']
        
        # 更新最高价/最低价（用于追踪止损）
        if side == 'long':
            if 'highest_price' not in position or current_price > position['highest_price']:
                position['highest_price'] = current_price
        else:  # short
            if 'lowest_price' not in position or current_price < position['lowest_price']:
                position['lowest_price'] = current_price
        
        # 更新持仓时间
        position['last_update'] = datetime.now()
    
    def record_trade(self, symbol: str, side: str, entry_price: float, 
                    exit_price: float, quantity: float, pnl: float):
        """
        记录交易
        
        参数:
            symbol: 交易对
            side: 方向
            entry_price: 入场价格
            exit_price: 出场价格
            quantity: 数量
            pnl: 盈亏
        """
        trade = {
            'timestamp': datetime.now(),
            'symbol': symbol,
            'side': side,
            'entry_price': entry_price,
            'exit_price': exit_price,
            'quantity': quantity,
            'pnl': pnl,
            'pnl_ratio': pnl / (entry_price * quantity) if entry_price * quantity > 0 else 0
        }
        
        self.trades_history.append(trade)
        
        # 更新统计
        self.stats['total_trades'] += 1
        self.stats['last_trade_time'] = datetime.now()
        
        if pnl > 0:
            self.stats['winning_trades'] += 1
            self.stats['total_profit'] += pnl
            self.stats['consecutive_losses'] = 0
        else:
            self.stats['losing_trades'] += 1
            self.stats['total_loss'] += abs(pnl)
            self.stats['consecutive_losses'] += 1
    
    def get_performance_metrics(self) -> Dict:
        """
        获取策略性能指标
        
        返回:
            性能指标字典
        """
        total_trades = self.stats['total_trades']
        if total_trades == 0:
            return {
                'total_trades': 0,
                'win_rate': 0.0,
                'profit_factor': 0.0,
                'net_profit': 0.0,
                'avg_win': 0.0,
                'avg_loss': 0.0
            }
        
        win_rate = self.stats['winning_trades'] / total_trades
        profit_factor = (self.stats['total_profit'] / self.stats['total_loss'] 
                        if self.stats['total_loss'] > 0 else float('inf'))
        net_profit = self.stats['total_profit'] - self.stats['total_loss']
        avg_win = (self.stats['total_profit'] / self.stats['winning_trades'] 
                  if self.stats['winning_trades'] > 0 else 0)
        avg_loss = (self.stats['total_loss'] / self.stats['losing_trades'] 
                   if self.stats['losing_trades'] > 0 else 0)
        
        return {
            'total_trades': total_trades,
            'winning_trades': self.stats['winning_trades'],
            'losing_trades': self.stats['losing_trades'],
            'win_rate': win_rate,
            'profit_factor': profit_factor,
            'net_profit': net_profit,
            'avg_win': avg_win,
            'avg_loss': avg_loss,
            'max_drawdown': self.stats['max_drawdown'],
            'consecutive_losses': self.stats['consecutive_losses']
        }
    
    def start(self):
        """启动策略"""
        self.is_running = True
        print(f"策略 {self.name} 已启动")
    
    def stop(self):
        """停止策略"""
        self.is_running = False
        print(f"策略 {self.name} 已停止")
    
    def reset(self):
        """重置策略状态"""
        self.positions = {}
        self.orders = {}
        self.trades_history = []
        self.stats = {
            'total_trades': 0,
            'winning_trades': 0,
            'losing_trades': 0,
            'total_profit': 0.0,
            'total_loss': 0.0,
            'max_drawdown': 0.0,
            'consecutive_losses': 0,
            'last_trade_time': None
        }
    
    def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name}, enabled={self.enabled}, running={self.is_running})"
